package com.baidu.disconf.client.config;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baidu.disconf.client.config.inner.DisInnerConfigAnnotation;
import com.baidu.disconf.client.support.DisconfAutowareConfig;
import com.baidu.disconf.core.common.constants.Constants;
import com.gitee.hermer.boot.jee.commons.bean.utils.BeanLocator;
import com.gitee.hermer.engine.jars.app.sdk.EngineAppClassLoader;
import com.gitee.hermer.engine.jars.core.domain.EngineConstant;


/**
 * Disconf Client鐨勭敤鎴烽厤缃枃浠�
 *
 * @author liaoqiqi
 * @version 2014-6-6
 */
public final class DisClientConfig {

	protected static final Logger LOGGER = LoggerFactory.getLogger(DisClientConfig.class);

	protected static ConcurrentHashMap<ClassLoader,DisClientConfig> INSTANCES = new ConcurrentHashMap<>();

	public static  DisClientConfig getInstance() {
		synchronized (INSTANCES) {
			ClassLoader key = Thread.currentThread().getContextClassLoader();
			if(INSTANCES.containsKey(key))
				return INSTANCES.get(key);
			DisClientConfig value = new DisClientConfig();
			INSTANCES.put(key, value);
			return value;
		}
	}

	public static boolean release(){
		synchronized (INSTANCES) {
			return INSTANCES.remove(Thread.currentThread().getContextClassLoader()) != null;
		}

	}

	protected static final String filename = EngineConstant.ENGINE_CONFIG_PROPERTIES_FILE_NAME;


	// disconf.properties 鐨勮矾寰� -D 浼犲叆
	private static final String DISCONF_CONF_FILE_PATH_ARG = "disconf.conf";

	private boolean isLoaded = false;



	public synchronized boolean isLoaded() {
		return isLoaded;
	}

	/**
	 * load config normal
	 *
	 * @throws Exception
	 */
	public synchronized void loadConfig(String filePath) throws Exception {

		if (isLoaded) {
			return;
		}

		String filePathInternal = filename;

		// 鎸囧畾鐨勮矾寰�
		if (filePath != null) {
			filePathInternal = filePath;
		}

		// -d 鐨勮矾寰�
		// 浼樺厛浣跨敤 绯荤粺鍙傛暟鎴栧懡浠よ瀵煎叆
		String disconfFilePath = System.getProperty(DISCONF_CONF_FILE_PATH_ARG);
		if (disconfFilePath != null) {
			filePathInternal = disconfFilePath;
		}

		DisClientConfig INSTANCE = INSTANCES.get(Thread.currentThread().getContextClassLoader());

		try {
			DisconfAutowareConfig.autowareConfig(INSTANCE, filePathInternal);
		} catch (Exception e) {
			LOGGER.warn("cannot find " + filePathInternal + ", using sys var or user input.");
		}

		// 浣跨敤system env 瀵煎叆
		DisconfAutowareConfig.autowareConfigWithSystemEnv(INSTANCE);
		isLoaded = true;
	}

	/**
	 * 閰嶇疆鏂囦欢鏈嶅姟鍣� HOST
	 */
	public static final String CONF_SERVER_HOST_NAME = EngineConstant.PROPERTIES_VALUE_KEY_DISCONF_CONF_SERVER_HOST;
	@DisInnerConfigAnnotation(name = CONF_SERVER_HOST_NAME)
	public String CONF_SERVER_HOST;

	private List<String> hostList;

	/**
	 * app
	 *
	 * @author
	 * @since 1.0.0
	 */
	public static final String CONF_APP_NAME = EngineConstant.PROPERTIES_VALUE_KEY_DSM_APP_NAME;
	@DisInnerConfigAnnotation(name = CONF_APP_NAME)
	public String APP = null;

	/**
	 * 鐗堟湰
	 *
	 * @author
	 * @since 1.0.0
	 */
	public static final String CONF_APP_VERSION = EngineConstant.PROPERTIES_VALUE_KEY_DSM_APP_VERSION;
	@DisInnerConfigAnnotation(name = CONF_APP_VERSION)
	public String VERSION = null;


	private DisClientConfig() {
		if(Thread.currentThread().getContextClassLoader() instanceof EngineAppClassLoader){
			try {
				APP = ((EngineAppClassLoader)Thread.currentThread().getContextClassLoader()).getCacheKey().split(EngineConstant.STR_SPLIT)[0];
				VERSION = ((EngineAppClassLoader)Thread.currentThread().getContextClassLoader()).getCacheKey().split(EngineConstant.STR_SPLIT)[1];
			} catch (Exception e) {
				LOGGER.error(e.getMessage(),e);
			}
		}
	}



	/**
	 * 涓绘垨澶�
	 *
	 * @author
	 * @since 1.0.0
	 */
	@DisInnerConfigAnnotation(name = "disconf.maintype")
	public String MAIN_TYPE;

	/**
	 * 閮ㄧ讲鐜
	 *
	 * @author
	 * @since 1.0.0
	 */
	public static final String ENV_NAME = "disconf.env";
	@DisInnerConfigAnnotation(name = DisClientConfig.ENV_NAME, defaultValue = Constants.DEFAULT_ENV)
	public String ENV = Constants.DEFAULT_ENV;

	/**
	 * 鏄惁浠庝簯绔笅杞介厤缃�
	 *
	 * @author
	 * @since 1.0.0
	 */
	private static final String ENABLE_REMOTE_CONF_NAME = "disconf.enable.remote.conf";
	@DisInnerConfigAnnotation(name = DisClientConfig.ENABLE_REMOTE_CONF_NAME, defaultValue = "false")
	public boolean ENABLE_DISCONF = false;

	/**
	 * 鏄惁寮�鍚疍EBUG妯″紡: 榛樿涓嶅紑鍚紝
	 * 1锛塼rue: 鐢ㄤ簬绾夸笅璋冭瘯锛屽綋ZK鏂紑涓巆lient杩炴帴鍚庯紙濡傛灉璁剧疆鏂偣锛岃繖涓簨浠跺緢瀹规槗灏卞彂鐢燂級锛孼K涓嶄細鍘婚噸鏂板缓绔嬭繛鎺ャ��
	 * 2锛塮alse: 鐢ㄤ簬绾夸笂锛屽綋ZK鏂紑涓巆lient杩炴帴鍚庯紝ZK浼氬啀娆″幓閲嶆柊寤虹珛杩炴帴銆�
	 *
	 * @author
	 * @since 1.0.0
	 */
	@DisInnerConfigAnnotation(name = "disconf.debug", defaultValue = "false")
	public boolean DEBUG = false;

	/**
	 * 蹇界暐鍝簺鍒嗗竷寮忛厤缃�
	 *
	 * @author
	 * @since 1.0.0
	 */
	@DisInnerConfigAnnotation(name = EngineConstant.PROPERTIES_VALUE_KEY_DISCONF_IGNORE, defaultValue = "")
	public String IGNORE_DISCONF_LIST = "";
	private Set<String> ignoreDisconfKeySet = new HashSet<String>();

	/**
	 * 鑾峰彇杩滅▼閰嶇疆 閲嶈瘯娆℃暟锛岄粯璁ゆ槸3娆�
	 *
	 * @author
	 * @since 1.0.0
	 */
	@DisInnerConfigAnnotation(name = EngineConstant.PROPERTIES_VALUE_KEY_DISCONF_CONF_SERVER_RETRY_TIMES, defaultValue = "3")
	public int CONF_SERVER_URL_RETRY_TIMES = 3;

	/**
	 * 鐢ㄦ埛鎸囧畾鐨� 涓嬭浇鏂囦欢澶�, 杩滅▼鏂囦欢涓嬭浇鍚庝細鏀惧湪杩欓噷
	 *
	 * @author
	 * @since 1.0.0
	 */
	@DisInnerConfigAnnotation(name = EngineConstant.PROPERTIES_VALUE_KEY_DISCONF_USER_DEFINE_DOWNLOAD_DIR, defaultValue = "./disconf/download")
	public String userDefineDownloadDir = "./disconf/download";

	/**
	 * 鑾峰彇杩滅▼閰嶇疆 閲嶈瘯鏃朵紤鐪犳椂闂达紝榛樿鏄�5绉�
	 *
	 * @author
	 * @since 1.0.0
	 */
	@DisInnerConfigAnnotation(name = EngineConstant.PROPERTIES_VALUE_KEY_DISCONF_CONF_SERVER_RETRY_SLEEP, defaultValue = "2")
	public int confServerUrlRetrySleepSeconds = 2;

	/**
	 * 璁╀笅杞芥枃浠跺す鏀惧湪 classpath鐩綍 涓�
	 *
	 * @author
	 * @since 1.0.0
	 */
	@DisInnerConfigAnnotation(name = "disconf.enable_local_download_dir_in_class_path", defaultValue = "true")
	public boolean enableLocalDownloadDirInClassPath = true;

	public List<String> getHostList() {
		return hostList;
	}

	public void setHostList(List<String> hostList) {
		this.hostList = hostList;
	}

	public Set<String> getIgnoreDisconfKeySet() {
		return ignoreDisconfKeySet;
	}

	public void setIgnoreDisconfKeySet(Set<String> ignoreDisconfKeySet) {
		this.ignoreDisconfKeySet = ignoreDisconfKeySet;
	}

}
